package org.framework.lazy.cloud.network.heartbeat.client.application.impl;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.client.application.LazyNettyServerPropertiesApplication;
import org.framework.lazy.cloud.network.heartbeat.client.application.assembler.LazyNettyServerPropertiesDTOAssembler;
import org.framework.lazy.cloud.network.heartbeat.client.application.command.lazy.netty.server.properties.*;
import org.framework.lazy.cloud.network.heartbeat.client.application.dto.LazyNettyServerPropertiesDTO;
import org.framework.lazy.cloud.network.heartbeat.client.config.NettyClientProperties;
import org.framework.lazy.cloud.network.heartbeat.client.config.PropertiesType;
import org.framework.lazy.cloud.network.heartbeat.client.domain.model.lazy.netty.server.properties.LazyNettyServerProperties;
import org.framework.lazy.cloud.network.heartbeat.client.domain.model.lazy.netty.server.properties.LazyNettyServerPropertiesRepository;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.NettyClientSocket;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.event.ClientChangeEvent;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.tcp.socket.NettyTcpClientSocket;
import org.framework.lazy.cloud.network.heartbeat.client.netty.permeate.udp.socket.NettyUdpClientSocket;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.enums.NettyClientStatus;
import org.framework.lazy.cloud.network.heartbeat.common.enums.ProtocolType;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.lazy.orm.web.plus.stereotype.LazyApplication;
import org.wu.framework.web.response.Result;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * describe 服务端配置信息
 *
 * @author Jia wei Wu
 * @date 2024/04/03 03:00 下午
 * @see org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyApplicationImpl
 **/
@Slf4j
@LazyApplication
public class LazyNettyServerPropertiesApplicationImpl implements LazyNettyServerPropertiesApplication {

    @Resource
    LazyNettyServerPropertiesRepository lazyNettyServerPropertiesRepository;

    @Resource
    private ClientChangeEvent clientChangeEvent;

    @Resource
    private List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList; // 处理服务端发送过来的数据类型

    @Resource
    private NettyClientProperties nettyClientProperties;// 默认配置文件配置


    // 缓存连接socket
    private final ConcurrentHashMap<LazyNettyServerProperties, NettyClientSocket> cacheNettyClientSocketMap = new ConcurrentHashMap<>();

    public static final ThreadPoolExecutor NETTY_CLIENT_EXECUTOR =
            new ThreadPoolExecutor(20, 50, 200, TimeUnit.MILLISECONDS,
                    new ArrayBlockingQueue<>(1));

    /**
     * describe 新增服务端配置信息
     *
     * @param lazyNettyServerPropertiesStoryCommand 新增服务端配置信息
     * @return {@link Result<LazyNettyServerProperties>} 服务端配置信息新增后领域对象
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<LazyNettyServerProperties> story(LazyNettyServerPropertiesStoryCommand lazyNettyServerPropertiesStoryCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesStoryCommand);

        // 如果状态正在运行中直接忽略
        lazyNettyServerPropertiesRepository.exists(lazyNettyServerProperties)
                .accept(exists -> {
                    if (!exists) {
                        starterOneClientSocket(lazyNettyServerProperties);
                    }
                });
        lazyNettyServerProperties.setType(PropertiesType.DB);
        return lazyNettyServerPropertiesRepository.story(lazyNettyServerProperties);
    }

    /**
     * describe 批量新增服务端配置信息
     *
     * @param lazyNettyServerPropertiesStoryCommandList 批量新增服务端配置信息
     * @return {@link Result<List<LazyNettyServerProperties>>} 服务端配置信息新增后领域对象集合
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<List<LazyNettyServerProperties>> batchStory(List<LazyNettyServerPropertiesStoryCommand> lazyNettyServerPropertiesStoryCommandList) {
        List<LazyNettyServerProperties> lazyNettyServerPropertiesList = lazyNettyServerPropertiesStoryCommandList.stream().map(LazyNettyServerPropertiesDTOAssembler.INSTANCE::toLazyNettyServerProperties).collect(Collectors.toList());
        return lazyNettyServerPropertiesRepository.batchStory(lazyNettyServerPropertiesList);
    }

    /**
     * describe 更新服务端配置信息
     *
     * @param lazyNettyServerPropertiesUpdateCommand 更新服务端配置信息
     * @return {@link Result<LazyNettyServerProperties>} 服务端配置信息领域对象
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<LazyNettyServerProperties> updateOne(LazyNettyServerPropertiesUpdateCommand lazyNettyServerPropertiesUpdateCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesUpdateCommand);
        return lazyNettyServerPropertiesRepository.story(lazyNettyServerProperties);
    }

    /**
     * describe 查询单个服务端配置信息
     *
     * @param lazyNettyServerPropertiesQueryOneCommand 查询单个服务端配置信息
     * @return {@link Result< LazyNettyServerPropertiesDTO >} 服务端配置信息DTO对象
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<LazyNettyServerPropertiesDTO> findOne(LazyNettyServerPropertiesQueryOneCommand lazyNettyServerPropertiesQueryOneCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesQueryOneCommand);
        return lazyNettyServerPropertiesRepository.findOne(lazyNettyServerProperties).convert(LazyNettyServerPropertiesDTOAssembler.INSTANCE::fromLazyNettyServerProperties);
    }

    /**
     * describe 查询多个服务端配置信息
     *
     * @param lazyNettyServerPropertiesQueryListCommand 查询多个服务端配置信息
     * @return {@link Result<List<LazyNettyServerPropertiesDTO>>} 服务端配置信息DTO对象
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<List<LazyNettyServerPropertiesDTO>> findList(LazyNettyServerPropertiesQueryListCommand lazyNettyServerPropertiesQueryListCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesQueryListCommand);
        return lazyNettyServerPropertiesRepository.findList(lazyNettyServerProperties).convert(lazyNettyServerPropertiesList -> lazyNettyServerPropertiesList.stream().map(LazyNettyServerPropertiesDTOAssembler.INSTANCE::fromLazyNettyServerProperties).collect(Collectors.toList()));
    }

    /**
     * describe 分页查询多个服务端配置信息
     *
     * @param lazyNettyServerPropertiesQueryListCommand 分页查询多个服务端配置信息
     * @return {@link Result<LazyPage<LazyNettyServerPropertiesDTO>>} 分页服务端配置信息DTO对象
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<LazyPage<LazyNettyServerPropertiesDTO>> findPage(int size, int current, LazyNettyServerPropertiesQueryListCommand lazyNettyServerPropertiesQueryListCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesQueryListCommand);
        return lazyNettyServerPropertiesRepository.findPage(size, current, lazyNettyServerProperties).convert(page -> page.convert(LazyNettyServerPropertiesDTOAssembler.INSTANCE::fromLazyNettyServerProperties));
    }

    /**
     * describe 删除服务端配置信息
     *
     * @param lazyNettyServerPropertiesRemoveCommand 删除服务端配置信息
     * @return {@link Result<LazyNettyServerProperties>} 服务端配置信息
     * @author Jia wei Wu
     * @date 2024/04/03 03:00 下午
     **/

    @Override
    public Result<LazyNettyServerProperties> remove(LazyNettyServerPropertiesRemoveCommand lazyNettyServerPropertiesRemoveCommand) {
        LazyNettyServerProperties lazyNettyServerProperties = LazyNettyServerPropertiesDTOAssembler.INSTANCE.toLazyNettyServerProperties(lazyNettyServerPropertiesRemoveCommand);
        // 关闭连接
        destroyOneClientSocket(lazyNettyServerProperties);
        return lazyNettyServerPropertiesRepository.remove(lazyNettyServerProperties);
    }

    /**
     * 启动socket
     *
     * @param lazyNettyServerProperties 配置
     */
    @Override
    public void starterOneClientSocket(LazyNettyServerProperties lazyNettyServerProperties) {
        boolean enabled = nettyClientProperties.isEnabled();
        if (enabled) {
            String inetHost = lazyNettyServerProperties.getInetHost();
            Integer inetPort = lazyNettyServerProperties.getInetPort();
            String clientId = lazyNettyServerProperties.getClientId();
            String appKey = lazyNettyServerProperties.getAppKey();
            String appSecret = lazyNettyServerProperties.getAppSecret();
            ProtocolType protocolType = lazyNettyServerProperties.getProtocolType();
            NettyClientSocket nettyClientSocket;
            if (ProtocolType.TCP.equals(protocolType)) {
                nettyClientSocket = new
                        NettyTcpClientSocket(inetHost, inetPort, clientId,
                         appKey, appSecret,
                        clientChangeEvent, handleChannelTypeAdvancedList);
            } else if (ProtocolType.UDP.equals(protocolType)) {
                nettyClientSocket = new
                        NettyUdpClientSocket(inetHost, inetPort, clientId,
                      appKey, appSecret,
                        clientChangeEvent, handleChannelTypeAdvancedList);
            } else {
                nettyClientSocket = null;
            }

            if (nettyClientSocket == null) {
                return;
            }

            cacheNettyClientSocketMap.put(lazyNettyServerProperties, nettyClientSocket);

            // 更新状态为运行中
            lazyNettyServerProperties.setConnectStatus(NettyClientStatus.RUNNING);
            lazyNettyServerPropertiesRepository.story(lazyNettyServerProperties);


            Thread thread = new Thread(() -> {
                try {
                    nettyClientSocket.newConnect2Server();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            });
            // 当前服务连接Netty客户端:{},Netty端口:{}
            log.info("Current service connection Netty client: {}, Netty port: {}", inetHost, inetPort);
            NETTY_CLIENT_EXECUTOR.execute(thread);

        }
    }

    /**
     * 启动所有 配置的socket
     */
    @Override
    public void starterAllClientSocket() {
        boolean enabled = nettyClientProperties.isEnabled();
        if (enabled) {
            // 查询所有配置
            lazyNettyServerPropertiesRepository.findList(new LazyNettyServerProperties()).accept(lazyNettyServerPropertiesDTOS -> {
                for (LazyNettyServerProperties nettyServerProperties : lazyNettyServerPropertiesDTOS) {
                    starterOneClientSocket(nettyServerProperties);
                }
            });
        }
    }

    /**
     * 关闭 客户端socket
     *
     * @param needCloseLazyNettyServerProperties 配置
     */
    @Override
    public void destroyOneClientSocket(LazyNettyServerProperties needCloseLazyNettyServerProperties) {
        // 关闭指定socket
        cacheNettyClientSocketMap.forEach(((nettyServerProperties, nettyTcpClientSocket) -> {
            String clientId = nettyServerProperties.getClientId();
            String inetHost = nettyServerProperties.getInetHost();
            Integer inetPort = nettyServerProperties.getInetPort();
            String needCloseInetHost = needCloseLazyNettyServerProperties.getInetHost();
            Integer needCloseInetPort = needCloseLazyNettyServerProperties.getInetPort();
            String needCloseClientId = needCloseLazyNettyServerProperties.getClientId();
            if (Objects.equals(clientId, needCloseClientId)
                    && Objects.equals(inetPort, needCloseInetPort)
                    && Objects.equals(inetHost, needCloseInetHost)) {
                nettyTcpClientSocket.shutdown();
                // 关闭客户端:{}与服务端连接:{}:{}
                log.warn("Close client: {} Connect to server: {}: {}", clientId, inetHost, inetPort);
            }
        }));
    }

    /**
     * 关闭 客户端socket
     */
    @Override
    public void destroyClientSocket() {
        // 关闭socket
        cacheNettyClientSocketMap.forEach(((nettyServerProperties, nettyTcpClientSocket) -> {
            nettyTcpClientSocket.shutdown();
            String clientId = nettyServerProperties.getClientId();
            String inetHost = nettyServerProperties.getInetHost();
            Integer inetPort = nettyServerProperties.getInetPort();
            // 关闭客户端:{}与服务端连接:{}:{}
            log.warn("Close client: {} Connect to server: {}: {}", clientId, inetHost, inetPort);
        }));
    }
}